﻿//------------------------------------------------------------------------------
// <copyright company="Tunynet">
//     Copyright (c) Tunynet Inc.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using Lucene.Net.Index;
using Lucene.Net.Search;
using System;

namespace Tunynet.Search
{
    /// <summary>
    /// 搜索管理器，用于管理Lucene近实时搜索的搜索器
    /// </summary>
    public class SearcherManager
    {
        private IndexSearcher searcher;
        private IndexWriter writer;
        private Object thisLock = new Object(); //线程锁

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="writer"></param>
        public SearcherManager(IndexWriter writer)
        {
            this.writer = writer;

            //使用IndexWriter的GetReader(）方法获取IndexReader，用于构建NRT搜索器
            this.searcher = new IndexSearcher(writer.GetReader());
        }

        /// <summary>
        /// 重新打开IndexReader，并构建新的搜索器
        /// </summary>
        public void Reopen()
        {
            lock (thisLock)
            {
                IndexSearcher oldSearcher = this.searcher;
                try
                {
                    oldSearcher.IndexReader.IncRef();

                    //判断IndexReader的状态，如果有索引更新，则IsCurrent()返回false
                    IndexReader indexReader = oldSearcher.IndexReader;
                    if (!indexReader.IsCurrent())
                    {
                        //重新打开IndexReader
                        IndexReader newReader = indexReader.Reopen();
                        if (newReader != indexReader)
                        {
                            //构建新的搜索器
                            this.searcher.IndexReader.DecRef();
                            this.searcher = new IndexSearcher(newReader);
                        }
                    }
                }
                finally
                {
                    oldSearcher.IndexReader.DecRef();
                }
            }
        }

        /// <summary>
        /// 获取搜索器，单线程运行
        /// </summary>
        /// <returns></returns>
        public IndexSearcher GetSearcher()
        {
            lock (thisLock)
            {
                //increments the refCount of this IndexReader instance. RefCounts are used to determine when a reader can be closed safely, i.e. as soon as there are no more references. Be sure to always call a corresponding decRef(), in a finally clause; otherwise the reader may never be closed. Note that close() simply calls decRef(), which means that the IndexReader will not really be closed until decRef() has been called for all outstanding references.
                this.searcher.IndexReader.IncRef();
                return this.searcher;
            }
        }

        /// <summary>
        /// 释放掉搜索器，单线程运行
        /// </summary>
        public void ReleaseSearcher()
        {
            this.ReleaseSearcher(this.searcher);
        }

        /// <summary>
        /// 释放掉搜索器，单线程运行
        /// </summary>
        public void ReleaseSearcher(IndexSearcher searcher)
        {
            lock (thisLock)
            {
                //decreases the refCount of this IndexReader instance. If the refCount drops to 0, then pending changes (if any) are committed to the index and this reader is closed.
                searcher.IndexReader.DecRef();
            }
        }

        /// <summary>
        /// 关闭当前搜索管理器中的IndexSearcher、IndexReader
        /// 注意：本操作并不会关闭IndexWriter
        /// </summary>
        public void Close()
        {
            this.ReleaseSearcher();
            this.searcher = null;
        }
    }
}